package com.mdd.admin.service.order.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.yulichang.query.MPJQueryWrapper;
import com.mdd.admin.LikeAdminThreadLocal;
import com.mdd.admin.config.wxpay.WxPayProperties;
import com.mdd.admin.service.course.ICourseService;
import com.mdd.admin.service.order.IOrderRefundService;
import com.mdd.admin.service.user.IUserService;
import com.mdd.admin.validate.common.PageParam;
import com.mdd.admin.validate.order.OrderRefundParam;
import com.mdd.admin.vo.order.*;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.course.StudyCourse;
import com.mdd.common.entity.order.*;
import com.mdd.common.entity.user.PointsLog;
import com.mdd.common.entity.user.User;
import com.mdd.common.enums.*;
import com.mdd.common.mapper.course.StudyCourseMapper;
import com.mdd.common.mapper.order.*;
import com.mdd.common.mapper.user.PointsLogMapper;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.utils.*;
import com.mdd.common.config.GlobalConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 订单退款实现类
 * @author panweiliang
 */
@Service
public class OrderRefundServiceImpl implements IOrderRefundService {
        
    @Resource
    OrderRefundMapper orderRefundMapper;

    @Resource
    OrderRefundLogMapper orderRefundLogMapper;

    @Resource
    OrderMapper orderMapper;

    @Resource
    OrderCourseMapper orderCourseMapper;

    @Resource
    private WxPayService wxService;

    @Resource
    private WxPayProperties properties;

    @Resource
    private ICourseService courseService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private AccountLogMapper accountLogMapper;

    @Resource
    private ConsumptionIncentivesMapper consumptionIncentivesMapper;

    @Resource
    private PointsLogMapper pointsLogMapper;

    /**
     * 订单退款列表
     *
     * @author panweiliang
     * @param pageParam 分页参数
     * @param params 搜索参数
     * @return PageResult<OrderRefundListVo>
     */
    @Override
    public PageResult<OrderRefundListVo> list(PageParam pageParam, Map<String, String> params) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<OrderRefund> mpjQueryWrapper = new MPJQueryWrapper<OrderRefund>()
                .selectAll(OrderRefund.class)
                .select("user.nickname as nickname, user.id as userId, user.avatar AS avatar, o.sn AS orderSn ")
                .innerJoin("?_user user ON user.id = t.user_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON o.id = t.order_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .orderByDesc(Arrays.asList("t.id"));

        if (StringUtil.isNotEmpty(params.get("keyword"))) {
            String keyword = params.get("keyword");
            mpjQueryWrapper.nested(wq->wq
                    .like("user.sn", keyword).or()
                    .like("user.nickname", keyword).or()
                    .like("user.mobile", keyword));
        }

        orderRefundMapper.setSearch(mpjQueryWrapper, params, new String[]{
                "like:sn@t.sn:str",
                "like:orderSn@o.sn:str",
                "datetime:startTime-endTime@t.create_time:str",
                "=:type@t.type:int",
                "=:refundStatus@t.refund_status:int",
        });
        IPage<OrderRefundListVo> iPage = orderRefundMapper.selectJoinPage(new Page<>(page, limit), OrderRefundListVo.class, mpjQueryWrapper);
        for(OrderRefundListVo item : iPage.getRecords()) {
            item.setAvatar(UrlUtil.toAbsoluteUrl(item.getAvatar()));
            item.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            item.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
        }
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }


    /**
     * 订单退款日志列表
     *
     * @author panweiliang
     * @param refundId 订单id
     * @return List<OrderRefundListVo>
     */
    public List<OrderRefundLogListVo> listLog(Integer refundId) {
        MPJQueryWrapper<OrderRefundLog> mpjQueryWrapper = new MPJQueryWrapper<OrderRefundLog>()
                .selectAll(OrderRefundLog.class)
                .select("user.nickname as operatorNickname, user.avatar AS operatorAvatar, refund.refund_amount AS refundAmount ")
                .innerJoin("?_order_refund refund ON refund.id = t.refund_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_user user ON user.id=t.operator_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.refund_id", refundId)
                .orderByDesc(Arrays.asList("t.id"));

        List<OrderRefundLogListVo> orderRefundLogListVoVos = orderRefundLogMapper.selectJoinList(OrderRefundLogListVo.class, mpjQueryWrapper);
        for(OrderRefundLogListVo item : orderRefundLogListVoVos) {
            item.setOperatorAvatar(UrlUtil.toAbsoluteUrl(item.getOperatorAvatar()));
            item.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            item.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
        }
        return orderRefundLogListVoVos;
    }

    @Override
    public Map<String, Object> statistics() {
        Map<String, Object> statistics = new LinkedHashMap<>();
        statistics.put("all_num", orderRefundMapper.countAll());
        statistics.put("afoot_num", orderRefundMapper.countByRefundStatus(0));
        statistics.put("success_num", orderRefundMapper.countByRefundStatus(1));
        statistics.put("fail_num", orderRefundMapper.countByRefundStatus(2));

        statistics.put("all_total_money", orderRefundMapper.getTotalMoney());
        statistics.put("afoot_total_money", orderRefundMapper.getTotalMoneyByRefundStatus(0));
        statistics.put("success_total_money", orderRefundMapper.getTotalMoneyByRefundStatus(1));
        statistics.put("fail_total_money", orderRefundMapper.getTotalMoneyByRefundStatus(2));
        return statistics;
    }

    /**
     * 订单退款新增
     *
     * @author panweiliang
     * @param orderRefundParam 参数
     */
    @Override
    public void add(OrderRefundParam orderRefundParam) throws WxPayException {
        Integer orderId = orderRefundParam.getOrderId();
        Order order = this.orderMapper.selectById(orderId);
        Assert.notNull(order, "订单数据不存在");

        Integer userId = order.getUserId();
        User user = this.userMapper.selectById(userId);
        Assert.notNull(user, "下单的用户不存在");

        Integer payWay = order.getPayWay();
        Assert.notNull(payWay, "无效订单");

        OrderRefund orderRefund = this.orderRefundMapper.selectOne(new QueryWrapper<OrderRefund>().eq("order_id", orderId).last("limit 1"));
        Assert.isNull(orderRefund, "该订单已存在退款，请不要重复操作");

        if (payWay.intValue() == OrderEnum.ORDER_PAY_WAY_WX.getCode()) {
            OrderRefund model = new OrderRefund();
            model.setSn(randMakeOrderRefundSn());
            model.setOrderId(orderRefundParam.getOrderId());
            model.setUserId(order.getUserId());
            model.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
            model.setOrderTerminal(order.getOrderTerminal());
            model.setTransactionId(order.getTransactionId());
            model.setOrderAmount(order.getOrderAmount());
            model.setRefundAmount(order.getOrderAmount());
            model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_ING.getCode());
            model.setCreateTime(System.currentTimeMillis() / 1000);
            model.setUpdateTime(System.currentTimeMillis() / 1000);
            orderRefundMapper.insert(model);
            WxPayRefundV3Request request = new WxPayRefundV3Request();
            request.setOutRefundNo(model.getSn());
            request.setNotifyUrl(this.properties.getOrderRefundNotifyUrl());
            request.setOutTradeNo(order.getSn());
            request.setTransactionId(order.getTransactionId());
            WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
            amount.setRefund(AmountUtil.yuan2Fen(order.getOrderAmount().toPlainString()));
            amount.setTotal(AmountUtil.yuan2Fen(order.getOrderAmount().toPlainString()));
            amount.setCurrency("CNY");
            request.setAmount(amount);
            WxPayRefundV3Result wxPayRefundV3Result = this.wxService.refundV3(request);
            String status = wxPayRefundV3Result.getStatus();
            int refundStatus = OrderRefundEnum.REFUND_STATUS_ING.getCode();
            String refundMsg = OrderRefundEnum.REFUND_STATUS_ING.getMsg();
            if ("SUCCESS".equals(status)) {
                refundStatus = OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode();
                refundMsg = OrderRefundEnum.REFUND_STATUS_SUCCESS.getMsg();
                order.setRefundStatus(OrderEnum.REFUND_STATUS_FULL.getCode());
                order.setRefundTime(TimeUtil.timestamp());
                this.orderMapper.updateById(order);
                model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                this.orderRefundMapper.updateById(model);
                OrderCourse orderCourse = orderCourseMapper.selectOne(new QueryWrapper<OrderCourse>().eq("order_id", order.getId()).last("limit 1"));
                if (orderCourse != null) {
                    Integer courseId = orderCourse.getCourseId();
                    this.courseService.delCourseStudy(userId, courseId);
                }
                dealPoints(user, order);
            } else if ("PROCESSING".equals(status)) {
                refundStatus = OrderRefundEnum.REFUND_STATUS_ING.getCode();
                refundMsg = OrderRefundEnum.REFUND_STATUS_ING.getMsg();
            } else if ("ABNORMAL".equals(status)) {
                refundStatus = OrderRefundEnum.REFUND_STATUS_FAIL.getCode();
                refundMsg = OrderRefundEnum.REFUND_STATUS_FAIL.getMsg();
            }
            OrderRefundLog orderRefundLog = new OrderRefundLog();
            orderRefundLog.setRefundId(model.getId());
            orderRefundLog.setRefundStatus(refundStatus);
            orderRefundLog.setRefundMsg(refundMsg);
            orderRefundLog.setSn(model.getSn());
            orderRefundLog.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
            orderRefundLog.setOperatorId(LikeAdminThreadLocal.getAdminId());
            orderRefundLog.setWechatRefundId(wxPayRefundV3Result.getTransactionId());
            orderRefundLog.setCreateTime(TimeUtil.timestamp());
            orderRefundLog.setUpdateTime(TimeUtil.timestamp());
            this.orderRefundLogMapper.insert(orderRefundLog);
        } else if (payWay == OrderEnum.ORDER_PAY_WAY_BALANCE.getCode()) {
            //回收课程
            OrderCourse orderCourse = orderCourseMapper.selectOne(new QueryWrapper<OrderCourse>().eq("order_id", order.getId()).last("limit 1"));
            if (orderCourse != null) {
                Integer courseId = orderCourse.getCourseId();
                this.courseService.delCourseStudy(userId, courseId);
                OrderRefund model = new OrderRefund();
                model.setSn(randMakeOrderRefundSn());
                model.setOrderId(orderRefundParam.getOrderId());
                model.setUserId(order.getUserId());
                model.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
                model.setOrderTerminal(order.getOrderTerminal());
                model.setTransactionId(order.getTransactionId());
                model.setOrderAmount(order.getOrderAmount());
                model.setRefundAmount(order.getOrderAmount());
                model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                model.setCreateTime(System.currentTimeMillis() / 1000);
                model.setUpdateTime(System.currentTimeMillis() / 1000);
                orderRefundMapper.insert(model);

                OrderRefundLog orderRefundLog = new OrderRefundLog();
                orderRefundLog.setRefundId(model.getId());
                orderRefundLog.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                orderRefundLog.setRefundMsg(OrderRefundEnum.REFUND_STATUS_SUCCESS.getMsg());
                orderRefundLog.setSn(model.getSn());
                orderRefundLog.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
                orderRefundLog.setOperatorId(LikeAdminThreadLocal.getAdminId());
                orderRefundLog.setWechatRefundId(null);
                orderRefundLog.setCreateTime(TimeUtil.timestamp());
                orderRefundLog.setUpdateTime(TimeUtil.timestamp());
                this.orderRefundLogMapper.insert(orderRefundLog);

                order.setRefundStatus(OrderEnum.REFUND_STATUS_FULL.getCode());
                order.setRefundTime(TimeUtil.timestamp());
                this.orderMapper.updateById(order);

                BigDecimal userMoney = user.getUserMoney();
                userMoney = userMoney != null ? userMoney : new BigDecimal("0");


                BigDecimal totalOrderAmount = user.getTotalOrderAmount();
                totalOrderAmount = totalOrderAmount != null ? totalOrderAmount : new BigDecimal("0");

                Long totalOrderNum = user.getTotalOrderNum();

                BigDecimal orderAmount = order.getOrderAmount();
                orderAmount = orderAmount != null ? orderAmount : new BigDecimal("0");

                userMoney = userMoney.add(orderAmount);
                AccountLog accountLog = new AccountLog();
                accountLog.setUserId(userId);
                accountLog.setChangeAmount(orderAmount);
                accountLog.setChangeType(AccountChangeEnum.BNW_INC_REFUND.getCode());
                accountLog.setRemark("订单退款");
                accountLog.setAssociationSn(order.getSn());
                accountLog.setLeftAmount(userMoney);
                accountLog.setAction(AccountChangeEnum.ACTION_INC.getCode());
                accountLog.setCreateTime(TimeUtil.timestamp());
                accountLog.setUpdateTime(TimeUtil.timestamp());
                this.accountLogMapper.insert(accountLog);
                user.setUserMoney(userMoney);
                totalOrderAmount = totalOrderAmount.subtract(orderAmount);
                user.setTotalOrderNum(totalOrderNum - 1);
                user.setTotalOrderAmount(totalOrderAmount);
                //需要增加账户变动信息
                this.userMapper.updateById(user);

                dealPoints(user, order);
            }
        }
    }

    @Override
    public void parseRefundNotify(String jsonData, SignatureHeader signatureHeader) throws WxPayException {
        WxPayRefundNotifyV3Result.DecryptNotifyResult result = this.wxService.parseRefundNotifyV3Result(jsonData, signatureHeader).getResult();
        String status = result.getRefundStatus();
        String orderSn = result.getOutTradeNo();
        String refundSn = result.getOutRefundNo();
        String transactionId = result.getTransactionId();
        Order order = orderMapper.selectOne(new QueryWrapper<Order>()
                .eq("sn", orderSn)
                .last("limit 1"));

        OrderRefund model = orderRefundMapper.selectOne(new QueryWrapper<OrderRefund>()
                .eq("sn", refundSn)
                .last("limit 1"));
        if (order != null && model != null) {
            Integer userId = order.getUserId();
            User user = userMapper.selectById(userId);
            int refundedStatus = model.getRefundStatus();
            if (OrderRefundEnum.REFUND_STATUS_ING.getCode() == refundedStatus) {
                int refundStatus = OrderRefundEnum.REFUND_STATUS_ING.getCode();
                String refundMsg = OrderRefundEnum.REFUND_STATUS_ING.getMsg();
                if ("SUCCESS".equals(status)) {
                    refundStatus = OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode();
                    refundMsg = OrderRefundEnum.REFUND_STATUS_SUCCESS.getMsg();
                    order.setRefundStatus(OrderEnum.REFUND_STATUS_FULL.getCode());
                    order.setRefundTime(TimeUtil.timestamp());
                    this.orderMapper.updateById(order);
                    model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                    this.orderRefundMapper.updateById(model);
                    OrderCourse orderCourse = orderCourseMapper.selectOne(new QueryWrapper<OrderCourse>().eq("order_id", order.getId()).last("limit 1"));
                    if (orderCourse != null) {
                        Integer courseId = orderCourse.getCourseId();
                        this.courseService.delCourseStudy(order.getUserId(), courseId);
                    }

                    dealPoints(user, order);

                } else if ("ABNORMAL".equals(status)) {
                    refundStatus = OrderRefundEnum.REFUND_STATUS_FAIL.getCode();
                    refundMsg = OrderRefundEnum.REFUND_STATUS_FAIL.getMsg();
                    model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_FAIL.getCode());
                    this.orderRefundMapper.updateById(model);
                }

                OrderRefundLog orderRefundLog = new OrderRefundLog();
                orderRefundLog.setRefundId(model.getId());
                orderRefundLog.setRefundStatus(refundStatus);
                orderRefundLog.setRefundMsg(refundMsg);
                orderRefundLog.setSn(model.getSn());
                orderRefundLog.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
                orderRefundLog.setOperatorId(LikeAdminThreadLocal.getAdminId());
                orderRefundLog.setWechatRefundId(transactionId);
                orderRefundLog.setCreateTime(TimeUtil.timestamp());
                orderRefundLog.setUpdateTime(TimeUtil.timestamp());
                this.orderRefundLogMapper.insert(orderRefundLog);

            }
        }
    }

    @Override
    public void addAgain(OrderRefundParam orderRefundParam) throws WxPayException {
        Integer orderId = orderRefundParam.getOrderId();
        Order order = this.orderMapper.selectById(orderId);
        Assert.notNull(order, "订单数据不存在");
        Assert.isTrue(order.getPayWay().intValue() == OrderEnum.ORDER_PAY_WAY_WX.getCode(), "非微信支付，不可重新退款");
        Assert.isTrue(order.getRefundStatus().intValue() == OrderEnum.REFUND_STATUS_NO.getCode(), "当前订单已退款，不能再退款");
        OrderRefund model = this.orderRefundMapper.selectOne(new QueryWrapper<OrderRefund>().eq("order_id", order.getId()).last("limit 1"));
        if (model == null) {
            this.add(orderRefundParam);
            return;
        }
        model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_ING.getCode());
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        orderRefundMapper.updateById(model);
        WxPayRefundV3Request request = new WxPayRefundV3Request();
        request.setOutRefundNo(model.getSn());
        request.setNotifyUrl(this.properties.getOrderRefundNotifyUrl());
        request.setOutTradeNo(order.getSn());
        request.setTransactionId(order.getTransactionId());
        WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
        amount.setRefund(AmountUtil.yuan2Fen(order.getOrderAmount().toPlainString()));
        amount.setTotal(AmountUtil.yuan2Fen(order.getOrderAmount().toPlainString()));
        amount.setCurrency("CNY");
        request.setAmount(amount);
        WxPayRefundV3Result wxPayRefundV3Result = this.wxService.refundV3(request);
        String status = wxPayRefundV3Result.getStatus();
        int refundStatus = OrderRefundEnum.REFUND_STATUS_ING.getCode();
        String refundMsg = OrderRefundEnum.REFUND_STATUS_ING.getMsg();
        if ("SUCCESS".equals(status)) {
            refundStatus = OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode();
            refundMsg = OrderRefundEnum.REFUND_STATUS_SUCCESS.getMsg();
            order.setRefundStatus(OrderEnum.REFUND_STATUS_INCOMPLETE.getCode());
            order.setRefundTime(TimeUtil.timestamp());
            this.orderMapper.updateById(order);
            model.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
            this.orderRefundMapper.updateById(model);
            OrderCourse orderCourse = orderCourseMapper.selectOne(new QueryWrapper<OrderCourse>().eq("order_id", order.getId()).last("limit 1"));
            Integer userId = order.getUserId();
            User user = userMapper.selectById(userId);
            if (orderCourse != null) {
                Integer courseId = orderCourse.getCourseId();
                this.courseService.delCourseStudy(userId, courseId);
            }

            dealPoints(user, order);

        } else if ("PROCESSING".equals(status)) {
            refundStatus = OrderRefundEnum.REFUND_STATUS_ING.getCode();
            refundMsg = OrderRefundEnum.REFUND_STATUS_ING.getMsg();
        } else if ("ABNORMAL".equals(status)) {
            refundStatus = OrderRefundEnum.REFUND_STATUS_FAIL.getCode();
            refundMsg = OrderRefundEnum.REFUND_STATUS_FAIL.getMsg();
        }
        OrderRefundLog orderRefundLog = new OrderRefundLog();
        orderRefundLog.setRefundId(model.getId());
        orderRefundLog.setRefundStatus(refundStatus);
        orderRefundLog.setRefundMsg(refundMsg);
        orderRefundLog.setSn(model.getSn());
        orderRefundLog.setType(OrderRefundEnum.TYPE_ADMIN.getCode());
        orderRefundLog.setOperatorId(LikeAdminThreadLocal.getAdminId());
        orderRefundLog.setWechatRefundId(wxPayRefundV3Result.getTransactionId());
        orderRefundLog.setCreateTime(TimeUtil.timestamp());
        orderRefundLog.setUpdateTime(TimeUtil.timestamp());
        this.orderRefundLogMapper.insert(orderRefundLog);
    }


    private void dealPoints(User user, Order order) {
        BigDecimal userPoints = user.getUserPoints();
        //退款 将扣除积分返还
        BigDecimal IntegralDiscountPrice = order.getIntegralDiscountPrice();
        if (user != null && IntegralDiscountPrice != null && IntegralDiscountPrice.compareTo(BigDecimal.ZERO) != 0) {
//            String scaleStr = LsConfigUtil.get("point_deduction", "scale", "10");
//            BigDecimal scale = new BigDecimal(scaleStr);
            BigDecimal totalIntegral = order.getIntegralVal();
            totalIntegral = totalIntegral.setScale(0, BigDecimal.ROUND_UP);
            userPoints = userPoints != null ? userPoints : new BigDecimal("0");
            userPoints = userPoints.add(totalIntegral);

            PointsLog pointsLog = new PointsLog();
            pointsLog.setUserId(user.getId());
            pointsLog.setChangePoints(totalIntegral);
            pointsLog.setChangeType(PointsChangeEnum.BNW_INC_ORDER_CANCEL.getCode());
            pointsLog.setRemark("退款返还积分");
            pointsLog.setLeftPoints(userPoints);
            pointsLog.setAction(PointsChangeEnum.ACTION_INC.getCode());
            pointsLog.setAssociationSn(order.getSn());
            pointsLog.setCreateTime(TimeUtil.timestamp());
            pointsLog.setUpdateTime(TimeUtil.timestamp());
            this.pointsLogMapper.insert(pointsLog);
        }

        //退款 将奖励的积分扣除
        ConsumptionIncentives consumptionIncentives = this.consumptionIncentivesMapper.selectOne(new QueryWrapper<ConsumptionIncentives>().eq("user_id", user.getId()).eq("order_id", order.getId()).isNull("delete_time").last("limit 1"));
        if (consumptionIncentives != null) {
            Integer rewardType = consumptionIncentives.getRewardType();
            String rewardContentStr = consumptionIncentives.getRewardContent();
            if (rewardType != null && rewardType.intValue() == 1) {
                BigDecimal rewardContent = new BigDecimal(rewardContentStr);
                userPoints = userPoints != null ? userPoints : new BigDecimal("0");
                userPoints = userPoints.subtract(rewardContent);
                user.setUserPoints(userPoints);

                PointsLog pointsLog = new PointsLog();
                pointsLog.setUserId(user.getId());
                pointsLog.setChangePoints(rewardContent);
                pointsLog.setChangeType(PointsChangeEnum.BNW_DEC_ORDER_CANCEL.getCode());
                pointsLog.setRemark("退款扣除奖励的积分");
                pointsLog.setLeftPoints(userPoints);
                pointsLog.setAction(PointsChangeEnum.ACTION_DEC.getCode());
                pointsLog.setAssociationSn(order.getSn());
                pointsLog.setCreateTime(TimeUtil.timestamp());
                pointsLog.setUpdateTime(TimeUtil.timestamp());
                this.pointsLogMapper.insert(pointsLog);
            }
        }

        user.setUserPoints(userPoints);
        userMapper.updateById(user);
    }

    /**
     * 订单退款删除
     *
     * @author panweiliang
     * @param id 主键ID
     */
    @Override
    public void del(Integer id) {
        OrderRefund model = orderRefundMapper.selectOne(
                new QueryWrapper<OrderRefund>()
                    .eq("id", id)
                    .last("limit 1"));

        Assert.notNull(model, "数据不存在!");

        orderRefundMapper.delete(new QueryWrapper<OrderRefund>().eq("id", id));
    }


    @Override
    public Map<String, Object> getOrderStatistic() {
        Map<String, Object> statistic = new LinkedHashMap<>();
        statistic.put("refundedAmount", this.orderRefundMapper.getRefundedTotalAmount());
        statistic.put("refundCount", this.orderRefundMapper.countAll());
        return statistic;
    }

    @Override
    public void checkStatus() {
        List<OrderRefund> orderRefunds= this.orderRefundMapper.selectList(new QueryWrapper<OrderRefund>()
                .eq("refund_status", OrderRefundEnum.REFUND_STATUS_ING.getCode()));
        orderRefunds.forEach(item -> {
            String sn = item.getSn();
            try {
                WxPayRefundQueryV3Result wxPayRefundQueryV3Result = this.wxService.refundQueryV3(sn);
                String status = wxPayRefundQueryV3Result.getStatus();
                if ("SUCCESS".equals(status)) {
                    Order order = this.orderMapper.selectById(item.getOrderId());
                    item.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                    item.setUpdateTime(TimeUtil.timestamp());
                    this.orderRefundMapper.updateById(item);
                    order.setRefundStatus(OrderEnum.REFUND_STATUS_FULL.getCode());
                    order.setRefundTime(TimeUtil.timestamp());
                    this.orderMapper.updateById(order);
                    OrderRefundLog orderRefundLog = new OrderRefundLog();
                    orderRefundLog.setRefundId(item.getId());
                    orderRefundLog.setSn(item.getSn());
                    orderRefundLog.setType(item.getType());
                    orderRefundLog.setWechatRefundId(wxPayRefundQueryV3Result.getRefundId());
                    orderRefundLog.setRefundStatus(OrderRefundEnum.REFUND_STATUS_SUCCESS.getCode());
                    orderRefundLog.setRefundMsg("全部退款");
                    orderRefundLog.setUpdateTime(TimeUtil.timestamp());
                    orderRefundLog.setCreateTime(TimeUtil.timestamp());
                    this.orderRefundLogMapper.insert(orderRefundLog);
                    //回收课程
                    OrderCourse orderCourse = orderCourseMapper.selectOne(new QueryWrapper<OrderCourse>().eq("order_id", order.getId()).last("limit 1"));
                    if (orderCourse != null) {
                        Integer userId = order.getUserId();
                        Integer courseId = orderCourse.getCourseId();
                        this.courseService.delCourseStudy(userId, courseId);
                    }
                } else if ("PROCESSING".equals(status)) {
                } else if ("ABNORMAL".equals(status)) {
                    item.setRefundStatus(OrderRefundEnum.REFUND_STATUS_FAIL.getCode());
                    item.setUpdateTime(TimeUtil.timestamp());
                    this.orderRefundMapper.updateById(item);
                    OrderRefundLog orderRefundLog = new OrderRefundLog();
                    orderRefundLog.setRefundId(item.getId());
                    orderRefundLog.setSn(item.getSn());
                    orderRefundLog.setType(item.getType());
                    orderRefundLog.setWechatRefundId(wxPayRefundQueryV3Result.getRefundId());
                    orderRefundLog.setRefundStatus(OrderRefundEnum.REFUND_STATUS_FAIL.getCode());
                    orderRefundLog.setRefundMsg("退款失败");
                    orderRefundLog.setUpdateTime(TimeUtil.timestamp());
                    orderRefundLog.setCreateTime(TimeUtil.timestamp());
                    this.orderRefundLogMapper.insert(orderRefundLog);
                }
            } catch (WxPayException e) {
                item.setRefundStatus(OrderRefundEnum.REFUND_STATUS_FAIL.getCode());
                item.setUpdateTime(TimeUtil.timestamp());
                this.orderRefundMapper.updateById(item);
                OrderRefundLog orderRefundLog = new OrderRefundLog();
                orderRefundLog.setRefundId(item.getId());
                orderRefundLog.setSn(item.getSn());
                orderRefundLog.setType(item.getType());
                orderRefundLog.setRefundStatus(OrderRefundEnum.REFUND_STATUS_FAIL.getCode());
                orderRefundLog.setRefundMsg(e.getCustomErrorMsg());
                orderRefundLog.setUpdateTime(TimeUtil.timestamp());
                orderRefundLog.setCreateTime(TimeUtil.timestamp());
                this.orderRefundLogMapper.insert(orderRefundLog);
            }
        });
    }

    /**
     * 生成唯一订单号
     *
     * @author panweiliang
     * @return Integer
     */
    private String randMakeOrderRefundSn() {
        String sn;
        while (true) {
            sn = ToolsUtil.randomDigitString(18);
            OrderRefund snModel = orderRefundMapper.selectOne(new QueryWrapper<OrderRefund>()
                    .select("id")
                    .eq("sn", sn)
                    .last("limit 1"));
            if (snModel == null) {
                break;
            }
        }
        return sn;
    }

}
